package util

import (
	"crypto"
	"crypto/hmac"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/sha512"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
)

func HmacSha256Base64Encode(data, secret string) string {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(data))

	// return hex.EncodeToString(h.Sum(nil))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func HmacSha256HexEncode(data, secret string) string {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(data))

	return hex.EncodeToString(h.Sum(nil))
}

func HmacSha512Base64Encode(data, secret string) string {
	h := hmac.New(sha512.New, []byte(secret))
	h.Write([]byte(data))

	// return hex.EncodeToString(h.Sum(nil))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func HmacSha512HexEncode(data, secret string) string {
	h := hmac.New(sha512.New, []byte(secret))
	h.Write([]byte(data))

	return hex.EncodeToString(h.Sum(nil))
}

func SHA256(s string) string {
	ctx := sha256.New()
	ctx.Write([]byte(s))

	return hex.EncodeToString(ctx.Sum(nil))
}

func SHA512(s string) string {
	ctx := sha512.New()
	ctx.Write([]byte(s))

	return hex.EncodeToString(ctx.Sum(nil))
}

// MD5 MD5
func MD5(text string) string {
	ctx := md5.New()
	ctx.Write([]byte(text))

	return hex.EncodeToString(ctx.Sum(nil))
}

// privateKey pem格式私钥 -----BEGIN RSA PRIVATE KEY----- xxxx -----END RSA PRIVATE KEY-----
//
// result: if want base64 format, use: base64.StdEncoding.EncodeToString(result) to convert
func MD5WithRSA(privateKey []byte, text string) (result []byte, err error) {
	//解密pem格式的私钥
	block, _ := pem.Decode(privateKey)
	if block == nil {
		err = errors.New("private key decode error")
		return
	}

	key, err := x509.ParsePKCS1PrivateKey(privateKey)
	if err != nil {
		return
	}

	md5sum := md5.Sum([]byte(text))
	result, err = rsa.SignPKCS1v15(nil, key, crypto.MD5, md5sum[:])
	return
}

// publicKey: pem格式公钥 -----BEGIN RSA PUBLIC KEY----- xxxx -----END RSA PUBLIC KEY-----
//
// result: if want base64 format, use: base64.StdEncoding.EncodeToString(result) to convert
func RSAEncrypt(publicKey []byte, str string) (result []byte, err error) {
	//解密pem格式的公钥
	block, _ := pem.Decode(publicKey)
	if block == nil {
		err = errors.New("public key decode error")
		return
	}

	// 解析公钥
	pubKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
	if err != nil {
		return
	}

	//加密
	result, err = rsa.EncryptPKCS1v15(rand.Reader, pubKey, []byte(str))
	return
}

// RSADecrypt RSADecrypt
func RSADecrypt(privateKey []byte, encryptedString string) (string, error) {
	block, _ := pem.Decode(privateKey)
	if block == nil {
		return "", errors.New("Private key error block")
	}

	//解析PKCS1格式的私钥
	priv, err2 := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err2 != nil {
		return "", err2
	}

	// 解密
	result, err3 := rsa.DecryptPKCS1v15(rand.Reader, priv, []byte(encryptedString))
	if err3 != nil {
		return "", err3
	}

	return string(result[:]), nil
}

// RSADecryptHex RSADecryptHex
func RSADecryptHex(privateKey []byte, str string) (string, error) {
	ff, errHex := hex.DecodeString(str)
	if errHex != nil {
		return "", errHex
	}

	return RSADecrypt(privateKey, string(ff[:]))
}

func Base64(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))
}
